/**************************************************************/
/*  This file is licensed from, and is a trade secret of:     */
/*                                                            */
/*    Mercury Computer Systems, Incorporated                  */
/*    199 Riverneck Road                                      */
/*    Chelmsford, Massachusetts 01824-2820                    */
/*    United States of America                                */
/*    Telephone + 1 978 256-1300                              */
/*                                                            */
/*  Refer to your Software License Agreement for provisions   */
/*  on use, duplication, or disclosure.                       */
/*  US. Government users and prime contractors are also       */
/*  governed by the following Data Rights Notice:             */
/*  Use, duplication or disclosure by the US. Government is   */
/*  subject to the provisions set forth in FAR 52.227-14 for  */
/*  restricted rights or other agency data rights provisions  */
/*  on commercial software and documentation, as applicable.  */
/*                                                            */
/*  This file: (a) was developed at private expense, and no   */
/*  part was developed with government funds, (b) is a        */
/*  trade secret of Mercury Computer Systems, Inc. for the    */
/*  purposes of the Freedom of Information Act, (c) is        */
/*  "commercial computer software" subject to limited         */
/*  utilization as provided in the above noted Software       */
/*  License Agreement and (d) is in all respects data         */
/*  belonging exclusively to Mercury Computer Systems, Inc..  */
/*                                                            */
/**************************************************************/

/******************************************************************/
/* Copyright (c) 1999-2003, Mercury Computer Systems, Inc.,       */
/* Chelmsford MA.,and all third party embedded software sources.  */
/* All rights reserved under the Copyright laws of US. and        */
/* international treaties.                                        */
/*                                                                */
/* Patent Pending                                                 */
/******************************************************************/


//$COPYRIGHT_END

#include <iostream>
#include <tao/corba.h>
#include <tao/orbsvcs/orbsvcs/CosNamingC.h>
#include <SceOsMisc.h>
#include "CF__Resource_impl.h"

#define PARAMETER1	"NAMING_CONTEXT_IOR"
#define PARAMETER2	"NAME_BINDING"
#define PARAMETER3	"COMPONENT_IDENTIFIER"
#define PARAMETER4	"DLL_NAME"
#define PARAMETER5	"DLL_ENTRY_POINT"

//this is the number of parameters defined above
#define NUM_EXPECTED_PARAMS	5

using namespace std;

int
usage (char * progname)
{
  std::cout << "Usage:" << progname << " [ORB PARAMETERS] NAMING_CONTEXT_IOR value NAME_BINDING value COMPONENT_IDENTIFIER value" << endl;
  return 0;
}

/*
 * ----------------------------------------------------------------------
 * In the default set-up, the ResourceLoader is started in a separate
 * window for each component; the window closes when the ResourceLoader
 * terminates.  That approach, while reasonable, does not allow the
 * user to read any error messages that might be written to the console
 * before the console disappears.
 *
 * Therefore, to facilitate some debugging, we "panic" in case of error;
 * this function then sleeps forever, until the user terminates the
 * ResourceLoader manually (e.g., using Ctrl-C).
 * ----------------------------------------------------------------------
 */

void
panic ()
{
  cerr << "Panic. Please terminate." << endl;
  while (42) {
    SCE::OS::sleep (100000);
  }
}

int
main (int argc, char* argv[])
{
  CORBA::ORB_var orb;

  try {
    orb = CORBA::ORB_init (argc, argv);

    //expect naming context ior and name binding information
    if (argc < (2*NUM_EXPECTED_PARAMS + 1)) {
      usage (argv[0]);
      exit(1);
    }

    string namingContextIOR;
    string nameBinding;
    string componentID;

    string nameDll;
    string nameEntryPoint;

    // Poor-man's parse of the command line.
    for (int i = 1; i < argc; i++) {
      if (strcmp (argv[i], PARAMETER1) == 0) {
	namingContextIOR = argv[i+1];
      }
      else if (strcmp (argv[i], PARAMETER2) == 0) {
	nameBinding = argv[i+1];
      }
      else if (strcmp(argv[i], PARAMETER3) == 0) {
	componentID = argv[i+1];
      }
      else if (strcmp(argv[i], PARAMETER4) == 0) {
	nameDll = argv[i+1];
      }
      else if (strcmp(argv[i], PARAMETER5) == 0) {
	nameEntryPoint = argv[i+1];
      }
    }

    if (namingContextIOR == "" ||
	nameBinding == "" ||
	componentID == "" ||
	nameDll == "" ||
	nameEntryPoint == "") {
      usage (argv[0]);
      exit (1);
    }

    CORBA::Object_var pfobj = orb->resolve_initial_references ("RootPOA");
    PortableServer::POA_var rootPOA = PortableServer::POA::_narrow (pfobj);

    if (CORBA::is_nil (rootPOA)) {
      cerr << "Error Occurred in narrowing the POA." << endl << flush;
      panic ();
      return 1;
    }

    PortableServer::POAManager_var poa_mgr = rootPOA -> the_POAManager();
    poa_mgr -> activate();

    // Find the Naming Service.
#ifdef MCS_VERBOSE
    cout << "Finding the naming service ... " << flush;
#endif

    CORBA::Object_var naming_obj = orb->string_to_object (namingContextIOR.c_str());
    CosNaming::NamingContext_var namingContextRoot =
      CosNaming::NamingContext::_narrow (naming_obj.in());

    if (CORBA::is_nil (namingContextRoot.in())) {
#ifdef MCS_VERBOSE
      cout << "failed." << endl;
#endif
      cerr << "Error: Naming service not found." << endl;
      panic ();
      return 1;
    }

#ifdef MCS_VERBOSE
    cout << "found." << endl;
#endif

    /*
     * The component UUID should be in the form:
     * Component_InstantiationIdentifier:ApplicationName
     */

    CORBA::ULong index = componentID.rfind (":");

    if (index == string::npos) {
      cerr << "Error: The parameter that contains the component UUID could not be parsed." << endl
	   << "       It should be in the form: Component_InstantiationIdentifier:ApplicationName." << endl;
      panic ();
      return 1;
    }

    CORBA::ULong length = componentID.length ();

    string applicationName;
    string componentUUID;

    applicationName.assign (componentID, index+1, length-index);
    componentUUID.assign (componentID, 0, index);

    /*
     * Load the DLL, and look up the entrypoint.
     */

    // A handle to the dll.
    HINSTANCE hDll;

#ifdef MCS_VERBOSE
    cout << "Loading \"" << nameDll << "\" ... " << flush;
#endif

    hDll = LoadLibrary (nameDll.c_str());

    if (!hDll) {
#ifdef MCS_VERBOSE
      cout << "failed." << endl;
#endif
      cerr << "Error: Failed to load library \"" << nameDll << "\"." << endl;
      panic ();
      return 1;
    }

#ifdef MCS_VERBOSE
    cout << "done." << endl;
#endif

#ifdef MCS_VERBOSE
    cout << "Resolving entrypoint \"" << nameEntryPoint << "\" ... " << flush;
#endif

    POA_CF::Resource * (*ProcAdd) (const char*);
    ProcAdd = (POA_CF::Resource* (*) (const char *)) GetProcAddress (hDll, nameEntryPoint.c_str());

    if (!ProcAdd) {
#ifdef MCS_VERBOSE
      cout << "failed." << endl;
#endif
      cerr << "Error: Failed to find entrypoint \""
	   << nameEntryPoint
	   << "\" in library \""
	   << nameDll
	   << "\"."
	   << endl;
      panic ();
      return 1;
    }

#ifdef MCS_VERBOSE
    cout << "done." << endl;
#endif

    /*
     * The entrypoint creates a new resource servant.
     */

#ifdef MCS_VERBOSE
    cout << "Creating resource ... " << flush;
#endif

    POA_CF::Resource * The_Resource_impl = ProcAdd (componentUUID.c_str());

    if (!The_Resource_impl) {
#ifdef MCS_VERBOSE
      cout << "failed." << endl;
#endif
      cerr << "Error: Failed to create resource of type \""
	   << componentUUID
	   << "\"." << endl;
      panic ();
      return 1;
    }

#ifdef MCS_VERBOSE
    cout << "done." << endl;
#endif

#ifdef MCS_VERBOSE
    cout << "Activating resource ... " << flush;
#endif

    CF::Resource_var The_Resource = The_Resource_impl->_this();

#ifdef MCS_VERBOSE
    cout << "done." << endl;
#endif

#ifdef MCS_VERBOSE
    cout << "Resource UUID is \""
	 << The_Resource->identifier ()
	 << "\"." << endl;
#endif

#ifdef MCS_VERBOSE
    cout << "Binding to the Naming Service ... " << flush;
#endif

    CosNaming::Name name;
    name.length (1);
    name[0].id = nameBinding.c_str ();

    /*
     * Only the following Naming Service operations can be used, according
     * to the SCA spec: bind, bind_new_context, unbind, destroy, resolve.
     * Therefore, the rebind operation is not available. If bind fails
     * due to an existing binding, we must unbind first and then bind
     * again.
     */

    try {
      namingContextRoot->bind (name,The_Resource.in ());
    }
    catch (const CosNaming::NamingContext::AlreadyBound &) {
      namingContextRoot->unbind (name);
      namingContextRoot->bind (name,The_Resource.in());
    }

#ifdef MCS_VERBOSE
    cout << "done." << endl;
#endif

#ifdef MCS_VERBOSE
    cout << "Running. This process has PID " << getpid() << "." << endl;
#endif

    orb->run();

#ifdef MCS_VERBOSE
    cout << "Terminating." << endl;
#endif

    orb->shutdown (true);
  }
  catch (CORBA::Exception & ex) {
    cerr << "EXCEPTION " << ex << endl;
    panic ();
    return 1;
  }

  return 0;
}
